/**
 * ===========================================================================
 *
 *       Filename:  main.c
 *
 *    Description:
 *
 *        Version:  1.0
 *        Created:  2009/06/02 17时23分26秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Author (mn), Email@xxx.xxx
 *        Company:  xxx xxx
 *
 * ===========================================================================
 */

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <errno.h>

#include <gtk/gtk.h>

#include "win_main.h"

#include "handle.h"
#include "public.h"
#include "protocol.h"
#include "logout.h"

#define SERVER_IP	"127.0.0.1"
#define SERVER_PORT	30303

////////////////////////////////////////

// 创建一个非阻塞连接.
static int create_connect(char *addr, short port)
{
	struct sockaddr_in sin;
	int sockfd;
	struct  hostent *ht;

	sockfd = socket(AF_INET, SOCK_STREAM, 0);

	memset (&sin, 0, sizeof (sin));
/*
	ht = gethostbyname(addr);
	if(ht == NULL) {
		perror ("gethostbyname() error");
		return -1;
	}
	sin.sin_addr.s_addr = (in_addr_t)(ht->h_addr);
*/
	sin.sin_addr.s_addr = inet_addr(addr);
    sin.sin_port = htons (port);
    sin.sin_family = AF_INET;

	if(connect(sockfd, (struct sockaddr *)&sin, sizeof(struct sockaddr)) == -1) {
		LOGOUT(1, "connect() error : %s\n", strerror(errno));
		return -1;
	}

	fcntl(sockfd,F_SETFL,O_NONBLOCK);

	return sockfd;
}

// 读取用户连接数据放入接收队列.
static int read_date(struct u_session_t *session)
{
	int len;

	if(session->recvlen < DEF_BUFMAX) {
		len = read(session->conn, session->recvbuf+session->recvlen,
					DEF_BUFMAX-session->recvlen-1);
		if(len == -1) {
			LOGOUT(1, "read() error : %s\n", strerror(errno));
			return -1;
		}
		session->recvlen+=len;
	}
	session->recvbuf[session->recvlen]='\0';

	return len;
}

int pack_send(struct u_session_t *session, int type, char *data, int len)
{
	struct proto_head_t *header;
	char pkg_data[1024];

	if(sizeof(struct proto_head_t)+len >= sizeof(pkg_data)) {
		LOGOUT(1, "data too long [%d]\n", len);
		return -1;
	}

	header = (struct proto_head_t *)pkg_data;

	// 包头.
	header->magic = MAGICNUM;
	header->ver = VERNUM;
	header->num	= type;
	header->flag = 0;
	header->len = len;

	bcopy(data, pkg_data+sizeof(struct proto_head_t), len);

	return write_data(session, pkg_data, sizeof(struct proto_head_t)+len);
}

// 处理完用户消息后,发送最终结果.
int write_data(struct u_session_t *session, char *data, int len)
{
	int sndlen = 0;

	// 发送一次,如有剩余,下次再发.
	sndlen = write(session->conn, data, len);
	if(sndlen == -1) {
		LOGOUT(1, "write() error : %s\n", strerror(errno));
		return -1;
	}

	if(sndlen < len) {
		bcopy(data+sndlen, session->sendbuf+session->sendlen, len-sndlen);
		session->sendlen += (len-sndlen);
	}

	return sndlen;
}

// 等待网络数据.
int to_sockio(void *argc)
{
	int num, len;
	fd_set rdset;
	struct timeval tv;

	if(user_session.conn <= 0) {
		return 0;
	}

	FD_ZERO(&rdset);
	FD_SET(user_session.conn, &rdset);

	tv.tv_sec=0;
	tv.tv_usec=0;

	num = select(user_session.conn+1, &rdset, NULL, NULL, &tv);
	if(num == 0) {
		return 1;
	}
	if(num == -1) {
		LOGOUT(1, "select() error : %s\n", strerror(errno));
		return 0;
	}
	if(num == 1 && FD_ISSET(user_session.conn, &rdset)) {
		len = read_date(&user_session);
		if(len > 0) {
			msg_exec(&user_session);
		}
	}

	return 1;
}

////////////////////////////////////////

int main(int argc, char *argv[])
{
	LOGOPEN("Client", 9, LOGSTDOUT);

	gtk_init(&argc, &argv);

	// 协议初始化.
	msg_init();
	// 清空用户会话结构.
	memset(&user_session, '\0', sizeof(user_session));
	// 创建连接.
	user_session.conn = create_connect(SERVER_IP, SERVER_PORT);
	if(user_session.conn == -1) {
		LOGOUT(1, "connect server error\n");
		exit(-1);
	}
	// 添加定时器.读取网络数据.
	gtk_timeout_add(200, to_sockio, NULL);

	win_main_init();
	win_main_show();

	gtk_main();

	return 0;
}

